package com.appkubes.fintech.restful.util;

import com.alibaba.fastjson.JSON;
import com.appkubes.fintech.restful.util.interceptor.RetryIntercepter;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.apache.commons.lang3.Validate;

import java.io.IOException;
import java.net.URLEncoder;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * Created by xyl on 18-8-21.
 */
@Slf4j
public class MyOkHttpUtil {

    /**
     * 默认连接超时30秒
     */
    public static final int DEFAULT_CONNECTION_TIMEOUT = 30;

    /**
     * 默认读超时60秒
     */
    public static final int DEFAULT_READ_TIMEOUT = 60;

    public static final MediaType MEDIATYPE_JSON = MediaType.parse("application/json; charset=utf-8");

    // 默认client
    private static final OkHttpClient client = new OkHttpClient.Builder()
            .connectTimeout(DEFAULT_CONNECTION_TIMEOUT, TimeUnit.SECONDS)
            .readTimeout(DEFAULT_READ_TIMEOUT, TimeUnit.SECONDS)
            .addInterceptor(new RetryIntercepter(3))
            .build();

    private MyOkHttpUtil() {

    }

    /**
     * get请求
     *
     * @param url 请求url
     * @return 响应对象
     * @throws IOException io异常
     */
    public static Response get(String url) throws IOException {
        return get(client, url);
    }

    /**
     * get请求
     *
     * @param url 请求url
     * @return 响应对象
     * @throws IOException io异常
     */
    public static Response get(String url, Map<String, Object> params) throws IOException {
        return get(client, attachHttpGetParams(url, params));
    }

    public static Response getRetry(String url, Map<String, Object> params) throws IOException {
        url = attachHttpGetParams(url, params);
        OkHttpClient client = new OkHttpClient.Builder()
                .connectTimeout(800, TimeUnit.MILLISECONDS)
                .readTimeout(2500, TimeUnit.MILLISECONDS)
                //重试
                .addInterceptor(new RetryIntercepter(3))
                .build();
        Request request = new Request.Builder()
                .url(url)
                .build();
        return client.newCall(request).execute();
    }

    public static Response postRetry(String url, Map<String, Object> params) throws IOException {
        OkHttpClient client = new OkHttpClient.Builder()
                .connectTimeout(800, TimeUnit.MILLISECONDS)
                .readTimeout(2500, TimeUnit.MILLISECONDS)
                //重试
                .addInterceptor(new RetryIntercepter(3))
                .build();
        Request request = new Request.Builder()
                .url(url).post(RequestBody.create(JSON.toJSONString(params), MEDIATYPE_JSON))
                .build();
        return client.newCall(request).execute();
    }


    /**
     * 为HttpGet 的 url 方便的添加多个name value 参数。
     *
     * @param url
     * @param params
     * @return
     */
    public static String attachHttpGetParams(String url, Map<String, Object> params) {

        Iterator<String> keys = params.keySet().iterator();
        Iterator<Object> values = params.values().iterator();
        StringBuffer stringBuffer = new StringBuffer();
        stringBuffer.append("?");

        for (int i = 0; i < params.size(); i++) {
            String value = null;
            try {
                value = URLEncoder.encode(values.next().toString(), "utf-8");
            } catch (Exception e) {
                e.printStackTrace();
            }

            stringBuffer.append(keys.next() + "=" + value);
            if (i != params.size() - 1) {
                stringBuffer.append("&");
            }
        }

        return url + stringBuffer.toString();
    }


    /**
     * get请求，默认连接超时
     *
     * @param url                 请求url
     * @param readTimeoutInMillis 读超时时间，单位微秒
     * @return 响应对象，需要关闭
     * @throws IOException io异常
     */
    public static Response get(String url, int readTimeoutInMillis) throws IOException {
        Validate.notEmpty(url, "url can not be null.");

        OkHttpClient newClient = new OkHttpClient.Builder()
                .connectTimeout(DEFAULT_CONNECTION_TIMEOUT, TimeUnit.SECONDS)
                .readTimeout(readTimeoutInMillis, TimeUnit.MILLISECONDS)
                .build();

        Response response = get(newClient, url);
        return response;
    }

    /**
     * post表单
     *
     * @param url    请求地址
     * @param params 表单数据
     * @return 响应对象
     * @throws IOException io异常
     */
    public static Response post(String url, Map<String, String> params) throws IOException {
        Validate.notEmpty(params, "form body can not be null.");
        return postParam(client, url, params);
    }

    /**
     * post表单
     *
     * @param url                 请求地址
     * @param params              表单数据
     * @param readTimeoutInMillis 读超时时间，单位微秒
     * @return 响应对象
     * @throws IOException io异常
     */
    public static Response post(String url, Map<String, String> params, int readTimeoutInMillis) throws IOException {
        Validate.notEmpty(params, "form body can not be null.");

        OkHttpClient newClient = new OkHttpClient.Builder()
                .connectTimeout(DEFAULT_CONNECTION_TIMEOUT, TimeUnit.SECONDS)
                .readTimeout(readTimeoutInMillis, TimeUnit.MILLISECONDS)
                .build();

        return postParam(newClient, url, params);
    }

    /**
     * post json
     *
     * @param url  请求地址
     * @param json json
     * @return 返回
     * @throws IOException io异常
     */
    public static Response post(String url, String json) throws IOException {
        return postJson(client, url, json);
    }

    /**
     * post json
     *
     * @param url                 请求地址
     * @param json                json
     * @param readTimeoutInMillis 读超时，单位微秒
     * @return 响应对象
     * @throws IOException io异常
     */
    public static Response post(String url, String json, int readTimeoutInMillis) throws IOException {
        OkHttpClient newClient = new OkHttpClient.Builder()
                .connectTimeout(DEFAULT_CONNECTION_TIMEOUT, TimeUnit.SECONDS)
                .readTimeout(readTimeoutInMillis, TimeUnit.MILLISECONDS)
                .build();

        return postJson(newClient, url, json);
    }

    private static Response get(OkHttpClient client, String url) throws IOException {
        Request request = new Request.Builder()
                .url(url)
                .build();

        Response response = client.newCall(request).execute();
        return response;
    }

    public static Response postParam(OkHttpClient httpClient, String url, Map<String, String> params) throws IOException {
        FormBody.Builder builder = new FormBody.Builder();
        params.forEach((k, v) -> builder.add(k, v));
        FormBody body = builder.build();

        Request request = new Request.Builder()
                .url(url)
                .post(body)
                .build();

        return httpClient.newCall(request).execute();
    }

    private static Response postParam(OkHttpClient httpClient, String url, Map<String, String> params, Map<String, String> headers) throws IOException {
        FormBody.Builder builder = new FormBody.Builder();
        params.forEach((k, v) -> builder.add(k, v));
        FormBody body = builder.build();

        Headers.Builder headerBuilder = new Headers.Builder();
        headers.forEach(((k, v) -> headerBuilder.add(k, v)));
        Headers headers1 = headerBuilder.build();


        Request request = new Request.Builder()
                .url(url)
                .post(body)
                .headers(headers1)
                .build();

        return httpClient.newCall(request).execute();
    }

    private static Response postJson(OkHttpClient httpClient, String url, String json) throws IOException {
        RequestBody body = RequestBody.create(MEDIATYPE_JSON, json);
        Request request = new Request.Builder()
                .url(url)
                .post(body)
                .build();
        return httpClient.newCall(request).execute();
    }


    /**
     * post json
     *
     * @param url 请求地址
     * @return 返回
     * @throws IOException io异常
     */
    public static String postForBody(String url, Map<String, String> params) {
        Validate.notEmpty(params, "form body can not be null.");

        OkHttpClient newClient = new OkHttpClient.Builder()
                .connectTimeout(DEFAULT_CONNECTION_TIMEOUT, TimeUnit.SECONDS)
                .readTimeout(DEFAULT_READ_TIMEOUT, TimeUnit.SECONDS)
                .build();

        Response response = null;
        try {
            response = postParam(newClient, url, params);
            return new String(response.body().bytes(), "UTF-8");
        } catch (IOException e) {
            log.info("", e);
            return null;
        }
    }

    /**
     * post json
     *
     * @param url 请求地址
     * @return 返回
     * @throws IOException io异常
     */
    public static String postForBody(String url, Map<String, String> params, Map<String, String> headers) {
        Validate.notEmpty(params, "form body can not be null.");
        Validate.notEmpty(headers, "headers can not be null.");

        OkHttpClient newClient = new OkHttpClient.Builder()
                .connectTimeout(DEFAULT_CONNECTION_TIMEOUT, TimeUnit.SECONDS)
                .readTimeout(DEFAULT_READ_TIMEOUT, TimeUnit.SECONDS)
                .build();

        Response response = null;
        try {
            response = postParam(newClient, url, params, headers);
            return new String(response.body().bytes(), "UTF-8");
        } catch (IOException e) {
            log.info("", e);
            return null;
        }
    }


}
